/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.p4;

import com.example.p4.R;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.Window;

/**
 * Snake: a simple game that everyone can enjoy.
 * 
 * This is an implementation of the classic Game "Snake", in which you control a
 * serpent roaming around the garden looking for apples. Be careful, though,
 * because when you catch one, not only will you become longer, but you'll move
 * faster. Running into yourself or the walls will end the game.
 * 
 */
public class Maze extends Activity {

    private MazeView mSnakeView;
    
    public static final int PAUSE = 0;
    public static final int READY = 1;
    public static final int RUNNING = 2;
    public static final int LOSE = 3;
    public static final int WIN = 4;
    protected static int mMode = READY;
    
    private static String ICICLE_KEY = "snake-view";
    
    protected int titleBarHeight = -1;
    
    private long endTime = 0;

    /**
     * Called when Activity is first created. Turns off the title bar, sets up
     * the content views, and fires up the SnakeView.
     * 
     */
    @Override
    public void onStart() {
        super.onStart();
        
        try{
        	testFunctionality();
        }catch(Exception e)
        {
        	Log.e("Error!", "Error occured during testing of functionality of Maze");
        	finish();
        }
        
        setContentView(R.layout.maze_layout);
        
        mMode = READY;
        mSnakeView = (MazeView) findViewById(R.id.maze_game_layout);
        mSnakeView.resetGame();
        
        DisplayMetrics metrics = new DisplayMetrics();
    	getWindowManager().getDefaultDisplay().getMetrics(metrics);

    	Log.d("Screen", "("+metrics.widthPixels+","+metrics.heightPixels+")");
    	mSnakeView.setScreenResolution(metrics.widthPixels, metrics.heightPixels);
        
        doTheAutoRefresh();
    }
    
    @Override
    public void onPause()
    {
    	mSnakeView.resetGame();
    	mMode = READY;
    	System.gc();
    	finish();
    	super.onPause();
    }
    
    
    private void testFunctionality() throws Exception
    {
    	try{
    		getTitleBarHeight();
    	}
    	catch(Exception e)
    	{
    		throw new Exception("getTitleBarHeight() returned an invalid value");
    	}
    }
    
    private int getTitleBarHeight()
    {
    	Rect rectgle= new Rect();
    	Window window= getWindow();
    	window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
    	int StatusBarHeight= rectgle.top;
    	int contentViewTop= 
    	    window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
    	int TitleBarHeight= StatusBarHeight - contentViewTop;
    	return TitleBarHeight;
    }
    
    public void startGame()
    {
    	mSnakeView.initSnakeView();
   	 	mSnakeView.initNewGame();
   	 	endTime = System.currentTimeMillis() + 4000;
        setMode(RUNNING);
    }
    
    public void setScore(double score)
    {
    	Intent data = new Intent();
    	data.putExtra("score", (double)score);
    	
    	if (getParent() == null) {
    	    setResult(Activity.RESULT_OK, data);
    	} else {
    	    getParent().setResult(Activity.RESULT_OK, data);
    	}
    }
    
    public void invokeWin()
    {
    	Log.d("GameEvent", "Game Won!");
    	setScore(30);
    	setWinScreen();
    	stopActivity();
    }
    
    public void invokeLoss()
    {
    	Log.d("GameEvent", "Game Loss...");
    	setScore(0);
    	setLoseScreen();
    	stopActivity();
    }
    
    private void setWinScreen()
    {
    	mSnakeView.setMode(MazeView.MODE_WIN);
    	mSnakeView.invalidate();
    }
    private void setLoseScreen()
    {
    	mSnakeView.setMode(MazeView.MODE_LOSE);
    	mSnakeView.invalidate();
    }
    
    public void stopActivity()
    {
    	Log.d("GameEvent", "Stopping activity");
    	update();
    	finish();
    }
    
    @Override
    public void onSaveInstanceState(Bundle outState) {
        //Store the game state
        outState.putBundle(ICICLE_KEY, mSnakeView.saveState());
    }
    
    public void setMode(int newMode) {
        mMode = newMode;
    }
    
    public void restoreState(Bundle icicle) {
        setMode(PAUSE);

        mSnakeView.mScore = icicle.getLong("mScore");
    }
    
    private void checkWin()
    {
    	if(mSnakeView.touchTrail.size() == 0)
    		return;
    	if(mSnakeView.touchTrail.get(mSnakeView.touchTrail.size()-1).y > mSnakeView.levelHeight*(MazeView.numOfLevels-1))
    		setMode(Maze.WIN);
    }
    
    
    private void checkLose()
    {
    	if(endTime-System.currentTimeMillis() < 0)
    		setMode(Maze.LOSE);
    }
    
    
    @Override
    public boolean onTouchEvent(MotionEvent e) {
        // MotionEvent reports input details from the touch screen
        // and other input controls. In this case, you are only
        // interested in events where the touch position changed.
    	
    	if(titleBarHeight == -1)
    	{
    		titleBarHeight = getTitleBarHeight();
    	}
        
        int tileX = (int)(e.getX() / MazeTileView.mTileSize);
        int tileY = (int)((e.getY()-titleBarHeight) / MazeTileView.mTileSize);

        switch(e.getAction())
        {
	        case MotionEvent.ACTION_CANCEL:
	        case MotionEvent.ACTION_UP:
	        	mSnakeView.onWallCollision();
	        	break;
	        case MotionEvent.ACTION_DOWN:
	        	if(mSnakeView.inStartArea(tileX, tileY))
	        		mSnakeView.addTouchPoint(tileX, tileY);
	        	break;
	        default:
	        	if(mSnakeView.touchTrail.size() > 0)
	        		mSnakeView.addTouchPoint(tileX, tileY);
	        	break;
        }
        
        mSnakeView.checkWallCollision();
        checkWin();
        
        return true;
    }

    public void update() {
		updateProgressBar();
        mSnakeView.clearTiles();
        mSnakeView.updateTrail();
        mSnakeView.updateMazeWalls();
        mSnakeView.updateStaticImages();
        mSnakeView.invalidate();
    }
    
    private void updateProgressBar()
    {
    	mSnakeView.progressBarPercent = ((double)(endTime-System.currentTimeMillis()))/4000;
    }
    
    private final static Handler handler = new Handler();
    
    private void doTheAutoRefresh() {
        handler.post(new Runnable() {
             public void run() {
        		 if(mMode == READY)
        			 startGame();
        		 else if (mMode == RUNNING)
        		 {
        			 update(); // this is where you put your refresh code
        		 	 checkLose();
        		 }
        		 else if(mMode == WIN){
        			 invokeWin();
        			 return;
        		 }
        		 else if (mMode == LOSE){
        			 invokeLoss();
        			 return;
        		 }
                 doTheAutoRefresh();                
             }
         });
    }
}
